﻿using System;
using System.Globalization;
using System.Linq;
using System.Security.Claims;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using System.Data;
using System.Reflection;
using System.Web.SessionState;
using app.Models;

namespace app.Api
{
    public class ApiBase
    {
        public static bool AllowApiExemption = false; // 免检
        private Dictionary<string, object> req_param_map = new Dictionary<string, object>(); // 已处理参数的缓存
        public Controller ctx { get; set; }
        public ApiBase(Controller the_ctx)
        {
            ctx = the_ctx;
            ctx.Session["base"] = this;
        }

        public IDENTITY UserIdentity {
            get
            {
                return ctx.Session["user_identity"] == null ? IDENTITY.VISITOR : (IDENTITY)ctx.Session["user_identity"];
            }
            set
            {
                ctx.Session["user_identity"] = value;
            }
        }
        public string UserRole
        {
            get
            {
                return ctx.Session["user_role"] == null ? "" : ctx.Session["user_role"].ToString();
            }
            set
            {
                ctx.Session["user_role"] = value;
            }
        }
        public string UserCode
        {
            get
            {
                return ctx.Session["user_code"] == null ? "" : ctx.Session["user_code"].ToString();
            }
            set
            {
                ctx.Session["user_code"] = value;
            }
        }
        public string Token
        {
            get
            {
                return ctx.Session["token"] == null ? "" : ctx.Session["token"].ToString();
            }
            set
            {
                ctx.Session["token"] = value;
            }
        }
        public string UserPermission
        {
            get
            {
                return ctx.Session["permission"] == null ? "" : ctx.Session["permission"].ToString();
            }
            set
            {
                ctx.Session["permission"] = value;
            }
        }

        #region 请求参数
        // token令牌参数
        public string req_token { get { return GetStringParam(new ReqStringParamOption { Name = "token" }); } }
        // 测试使用参数
        public int req_exemption { get { return GetIntParam(new ReqIntParamOption { Name = "exemption", Level = REQPARAMLEVEL.FREE, DefaultValue = 0 }); } }
        // 分页参数
        public int req_current_page { get { return GetIntParam(new ReqIntParamOption { Name = "current_page", Level = REQPARAMLEVEL.VALID, DefaultValue = 1 }); } }
        public int req_page_size { get { return GetIntParam(new ReqIntParamOption { Name = "page_size", Level = REQPARAMLEVEL.VALID, DefaultValue = 100 }); } }
        public int req_list_size { get { return GetIntParam(new ReqIntParamOption { Name = "list_size", Level = REQPARAMLEVEL.VALID, DefaultValue = 100 }); } }
        // 常用公有属性  
        public int req_id { get { return GetIntParam(new ReqIntParamOption { Name = "id" }); } }
        public int req_type { get { return GetIntParam(new ReqIntParamOption { Name = "type" }); } }
        public int req_status { get { return GetIntParam(new ReqIntParamOption { Name = "status" }); } }
        public string req_name { get { return GetStringParam(new ReqStringParamOption { Name = "name" }); } }
        public string req_username { get { return GetStringParam(new ReqStringParamOption { Name = "username" }); } }
        public string req_password { get { return GetStringParam(new ReqStringParamOption { Name = "password" }); } }
        public string req_remark { get { return GetStringParam(new ReqStringParamOption { Name = "remark" }); } }
        public string req_title { get { return GetStringParam(new ReqStringParamOption { Name = "title" }); } }
        #endregion

        #region 请求参数函数
        /*
            参数有三种情况
            1.参数不可缺，参数必须有效
            2.参数可缺，提供默认值，参数必须有效
            3.参数可缺可无效，提供默认值 
        */
        private T GetParamWithMap<T>(ReqParamOption<T> option, IReqParamOption Ioption)
        {
            if (req_param_map.ContainsKey(option.Name))
            {
                return (T)req_param_map[option.Name];
            }
            else
            {
                T value = GetParam<T>(option, Ioption);
                req_param_map.Add(option.Name, value);
                return value;
            }
        }
        private T GetParam<T>(ReqParamOption<T> option, IReqParamOption Ioption)
        {
            string error_prefix = "错误参数" + option.Name + ":";
            string value = ctx.Request[option.Name];
            // 首先检测是否为空值
            if (value == null || value == "undefined")
            {
                // 为空
                if (option.Level == REQPARAMLEVEL.MUST_VALID)
                {
                    ThrowStatus(option.LackStatus, error_prefix + option.LackMessage);
                }
                else
                {
                    return option.DefaultValue;
                }
            }
            else
            {
                // 不为空
                // 检测是否为正确类型
                if (Ioption.TypeTest(value))
                {
                    // 类型正确
                    // 检测是否是合法有效的值
                    if (option.InvalidTest(option.Result))
                    {
                        // 有效
                        return option.Result;
                    }
                    else
                    {
                        // 无效
                        ThrowStatus(option.InvalidStatus, error_prefix + option.InvalidMessage);
                    }
                }
                else
                {
                    // 类型错误
                    if (option.Level == REQPARAMLEVEL.FREE)
                    {
                        return option.DefaultValue;
                    }
                    else
                    {
                        ThrowStatus(option.TypeErrorStatus, error_prefix + option.TypeErrorMessage);
                    }
                }
            }
            return option.DefaultValue;
        }
        public string GetStringParam(ReqStringParamOption option)
        {
            return GetParamWithMap<string>(option, option);
        }
        public bool GetBooleanParam(ReqBooleanParamOption option)
        {
            return GetParamWithMap<bool>(option, option);
        }
        public T GetObjectParam<T>(ReqObjectParamOption<T> option)
        {
            return GetParamWithMap<T>(option, option);
        }
        public int GetIntParam(ReqIntParamOption option)
        {
            return GetParamWithMap<int>(option, option);
        }
        public double GetDoubleParam(ReqDoubleParamOption option)
        {
            return GetParamWithMap<double>(option, option);
        }
        public string GetTimeStampParam(ReqTimeStampParamOption option)
        {
            return GetParamWithMap<string>(option, option);
        }
        #endregion

        #region 其他函数
        // 将一个对象转成json字符串添加到response中
        public void ResponseJson(object obj)
        {
            ctx.Response.ContentType = "application/json";
            ctx.Response.Write(G.DB.ToJson(obj));
            ctx.Response.End();
        }
        // 抛出错误状态码
        public void ThrowStatus(STATUS status, string message = "")
        {
            ResponseJson(new MessageResult { status = (int)status, message = message });
            throw new ApiException();
        }
        #endregion

        #region 登入登出/检测权限
        public bool Login(IDENTITY identity)
        {
            string user_code = "";
            string user_permission = "";
            string user_role = "";
            if (identity == IDENTITY.ADMIN)
            {
                string test_str = string.Format("select * from {0} where username = '{1}' and password = '{2}'", G.DB.GetTableName<Admin>(), req_username, req_password);
                Admin admin = G.DB.Get(test_str).GetFirstEntity<Admin>();
                if (admin != null)
                {
                    user_code = admin.id.ToString();
                    user_permission = admin.permission;
                }
            }else if(identity == IDENTITY.MEMBER)
            {
                string test_str = string.Format("select * from {0} where username = '{1}' and password = '{2}'", G.DB.GetTableName<Member>(), req_username, req_password);
                Member member = G.DB.Get(test_str).GetFirstEntity<Member>();
                if (member != null)
                {
                    user_code = member.id.ToString();
                    user_permission = member.permission;
                    user_role = member.role_type;
                }
            }
            if(user_code != "")
            {
                bool force = HasPermission(identity, user_code, Permission.Module(PERMISSIONMODULE.LOGIN).Operation(PERMISSIONOPERATION.EXCLUSIVE));
                if (!force && LandingServer.GetUnitState(identity + user_code) == LANDINGSTATE.ONLINE) ThrowStatus(STATUS.HAS_LOGIN, "正在其他地方登陆");
                UserIdentity = identity;
                UserRole = user_role;
                UserCode = user_code;
                Token = DateTimeEx.GetNowTimeStamp();
                UserPermission = user_permission;
                LandingServer.AddUnit(UserIdentity + UserCode, Token);
                return true;
            }
            else
            {
                //ResponseJson(new BooleanResult { value = false, message = "用户名或密码错误" });
                return false;
            }
        }
        public void Logout()
        {
            LandingServer.RemoveUnit(UserIdentity + UserCode, Token);
            ctx.Session.Contents.Remove("user_identity");
            ctx.Session.Contents.Remove("user_code");
            ctx.Session.Contents.Remove("token");
            ctx.Session.Contents.Remove("permission");
        }
        public void CheckPermission(IDENTITY identity, PermissionOperation operation)
        {
            if (identity != IDENTITY.VISITOR && UserIdentity == IDENTITY.VISITOR) ThrowStatus(STATUS.HASNOT_LOGIN, "您没有登录或session失效，请重新登录！");
            // 检测是否登陆，也有可能被挤下线
            if (!LandingServer.IsValid(UserIdentity + UserCode, Token))
            {
                if(LandingServer.GetUnitState(UserIdentity+UserCode) != LANDINGSTATE.OFFLINE)
                {
                    ThrowStatus(STATUS.FORCED_OFFLINE, "当前账号在其他设备登陆，请重新登陆！");
                }
                else
                {
                    ThrowStatus(STATUS.HASNOT_LOGIN, "您没有登录或session失效，请重新登录！");
                }
            }
            if (!HasPermission(identity, operation))
            {
                ThrowStatus(STATUS.NO_PERMISSION, string.Format("您没有访问权限，权限名称：{0}，权限码：{1}", operation.GetName(), operation.GetCode()));
                return;
            }
        }
        public bool HasPermission(IDENTITY identity, PermissionOperation operation)
        {
            // 免检，用于测试
            if (AllowApiExemption && req_exemption == 1) return true;

            // 解析token
            if (req_token != Token) return false;

            // 检测是否登陆，也有可能被挤下线
            if (!LandingServer.IsValid(UserIdentity + UserCode, Token)) return false;
            LandingServer.UpdateUnit(UserIdentity + UserCode, Token);

            // 检测身份
            if (identity == IDENTITY.VISITOR || identity == IDENTITY.ALL) return true;
            if (UserIdentity != identity) return false;

            // 检测权限
            if (operation == null) return true; // 如果operation为null，则不需要检测权限
            if (Permission.Check(UserPermission, operation.GetCode())) return true;
            else return false;
        }
        public bool HasPermission(IDENTITY identity)
        {
            return HasPermission(identity, null);
        }
        // 仅仅检测是否有权限，不考虑是否登陆问题
        public bool HasPermission(IDENTITY identity, string code, PermissionOperation operation)
        {
            // 检测权限
            if (operation == null) return true; // 如果operation为null，则不需要检测权限
            string permission = "";
            if (identity == IDENTITY.ADMIN) permission = G.DB.GetById<Admin>(code).permission;
            else if (identity == IDENTITY.MEMBER) permission = G.DB.GetById<Member>(code).permission;
            if (Permission.Check(permission, operation.GetCode())) return true;
            else return false;
        }
        #endregion

        #region list、分页
        public PageResult<T> GetPageResult<T>(string condition, string orderby_column) where T : class, new()
        {
            int current_page = req_current_page;
            int page_size = req_page_size;
            int total = G.DB.GetCount<T>(condition);
            int skip = (current_page - 1) * page_size;
            int take = page_size;
            List<T> list = G.DB.GetPage<T>(condition, orderby_column, skip, take).GetFirstTableList<T>();
            return new PageResult<T> { page = new PageData<T> { current_page = current_page, page_size = page_size, total = total, list = list } };
        }
        public ListResult<T> GetListResult<T>(string condition, string orderby_column = "") where T : class, new()
        {
            List<T> list = G.DB.Get<T>(condition, orderby_column, req_list_size).GetFirstTableList<T>();
            return new ListResult<T> { list = list };
        }
        #endregion
    }

    class ApiError : ApiBase
    {
        public ApiError(Controller ctx) : base(ctx)
        {
        }

        public void ErrorUrl(string id)
        {
            ResponseJson(new MessageResult { status = (int)STATUS.NO_RESOURCES, message = "错误路径" + id + ": 无效的api路径" });
        }

        public void HasException(Exception e)
        {
            ResponseJson(new MessageResult { status = (int)STATUS.NO_RESOURCES, message = "程序异常: " + e.Message });
        }
    }
}